#ifndef MW_CIPHER_H
#define MW_CIPHER_H


/** Meanwhile */


/** @file mw-cipher.h
    @since 2.0.0 */


#include <glib.h>
#include "mw-common.h"
#include "mw-object.h"


G_BEGIN_DECLS


typedef enum mw_cipher_mode {
  MW_CIPHER_MODE_RC2_40 = 0x0000,
  MW_CIPHER_MODE_RC2_128 = 0x0001,
} MwCipherMode;


GType mw_cipher_mode_get_type();


#define MW_TYPE_CIPHER_MODE (mw_cipher_mode_get_type())



typedef struct mw_encrypt {
  guint16 mode;
  MwOpaque info;
} MwEncrypt;


MwEncrypt *mw_encrypt_new();


MwEncrypt *mw_encrypt_dup(const MwEncrypt *e);


void mw_encrypt_copy(MwEncrypt *to, const MwEncrypt *from);


void mw_encrypt_read(MwReadBuffer *mwb, MwEncrypt *e, GError **err);


void mw_encrypt_write(MwWriteBuffer *mwb, const MwEncrypt *e);


void mw_encrypt_clear(MwEncrypt *t);


void mw_encrypt_free(MwEncrypt *e);


guint mw_encrypt_hash(const MwEncrypt *e);


gboolean mw_encrypt_equal(const MwEncrypt *a, const MwEncrypt *b);



typedef enum mw_cipher_state {
  /** cipher is not newly created */
  MW_CIPHER_STATE_NEW = MW_STATE_STOPPED,

  /** cipher has been offered by the local side */
  MW_CIPHER_STATE_OFFER = MW_STATE_STARTING | 0x01,

  /** cipher has been accepted by the remote side */
  MW_CIPHER_STATE_ACCEPTED = MW_STATE_STARTING | 0x02,

  /** cipher has been offered by the remote side */
  MW_CIPHER_STATE_OFFERED = MW_STATE_STARTING | 0x11,

  /** cipher has been accepted by the local side */
  MW_CIPHER_STATE_ACCEPT = MW_STATE_STARTING | 0x12,

  /** cipher is ready to use */
  MW_CIPHER_STATE_READY = MW_STATE_STARTED,

} MwCipherState;


GType mw_cipher_state_get_type();


#define MW_TYPE_CIPHER_STATE (mw_cipher_state_get_type())



typedef struct mw_cipher {
  MwObject mwobject;

} MwCipher;


typedef struct mw_cipher_class {
  MwObjectClass mwobjectclass;
  
  guint16 (*get_id)();
  guint16 (*get_policy)();

  MwEncrypt *(*offer)(MwCipher *self);
  void (*accepted)(MwCipher *self, const MwEncrypt *enc);

  void (*offered)(MwCipher *self, const MwEncrypt *enc);
  MwEncrypt *(*accept)(MwCipher *self);

  MwOpaque *(*encrypt)(MwCipher *self, const MwOpaque *data);
  MwOpaque *(*decrypt)(MwCipher *self, const MwOpaque *data);

} MwCipherClass;


#define MW_TYPE_CIPHER (mw_cipher_get_type())


#define MW_CIPHER(obj)						\
  (G_TYPE_CHECK_INSTANCE_CAST((obj), MW_TYPE_CIPHER, MwCipher))


#define MW_CIPHER_CLASS(klass)						\
  (G_TYPE_CHECK_CLASS_CAST((klass), MW_TYPE_CIPHER, MwCipherClass))


#define MW_IS_CIPHER(obj)				\
  (G_TYPE_CHECK_INSTANCE_TYPE((obj), MW_TYPE_CIPHER))


#define MW_IS_CIPHER_CLASS(klass)			\
  (G_TYPE_CHECK_CLASS_TYPE((klass), MW_TYPE_CIPHER))


#define MW_CIPHER_GET_CLASS(obj)					\
  (G_TYPE_INSTANCE_GET_CLASS((obj), MW_TYPE_CIPHER, MwCipherClass))


GType mw_cipher_get_type();


guint16 mw_cipher_class_get_identifier(MwCipherClass *klass);


guint16 mw_cipher_class_get_policy(MwCipherClass *klass);


MwCipher *mw_cipher_class_new_instance(MwCipherClass *klass);


MwEncrypt *mw_cipher_offer(MwCipher *self);


void mw_cipher_accepted(MwCipher *self, const MwEncrypt *enc);


void mw_cipher_offered(MwCipher *self, const MwEncrypt *enc);


MwEncrypt *mw_cipher_accept(MwCipher *self);


MwOpaque *mw_cipher_encrypt(MwCipher *self, const MwOpaque *data);


MwOpaque *mw_cipher_decrypt(MwCipher *self, const MwOpaque *data);



typedef struct mw_rc2_cipher {
  MwCipher cipher;

} MwRC2Cipher;


typedef struct mw_rc2_cipher_class {
  MwCipherClass cipherclass;

  void (*set_encrypt_key)(MwRC2Cipher *self, const MwOpaque *key);
  void (*set_decrypt_key)(MwRC2Cipher *self, const MwOpaque *key);
  
} MwRC2CipherClass;


#define MW_TYPE_RC2_CIPHER (mw_rc2_cipher_get_type())


GType mw_rc2_cipher_get_type();


void mw_rc2_cipher_set_encrypt_key(MwRC2Cipher *self, const MwOpaque *key);


void mw_rc2_cipher_set_decrypt_key(MwRC2Cipher *self, const MwOpaque *key);



typedef struct mw_rc2_dh_cipher {
  MwCipher cipher;

} MwRC2DHCipher;


typedef struct mw_rc2_dh_cipher_class {
  MwCipherClass cipherclass;

  void (*generate_local)(MwRC2DHCipher *self);
  void (*set_local)(MwRC2DHCipher *self, const MwMPI *local);
  const MwMPI *(*get_public)(MwRC2DHCipher *self);
  void (*set_remote)(MwRC2DHCipher *self, const MwMPI *remote);
  const MwMPI *(*get_shared)(MWRC2DHCipher *self);

} MwRC2DHCipherClass;


#define MW_TYPE_RC2_DH_CIPHER (mw_rc2_dh_cipher_get_type())


GType mw_rc2_dh_cipher_get_type();


void mw_rc2_dh_cipher_generate_local(MwRC2DHCipher *self);


void mw_rc2_dh_cipher_set_local(MwRC2DHCipher *self, const MwMPI *local);


const MwMPI *mw_rc2_dh_cipher_get_public(MwRC2DHCipher *self);


void mw_rc2_dh_cipher_set_remote(MwRC2DHCipher *self, const MwMPI *remote);


const MwMPI *mw_rc2_dh_cipher_get_shared(MwRC2DHCipher *self);



G_END_DECLS


#endif /* MW_CIPHER_H */
